package org.xiaov.lunasql.spring.mybatis;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.dromara.hutool.core.text.StrUtil;
import org.xiaov.lunasql.engine.transform.TransformManager;

import java.lang.reflect.Proxy;
import java.sql.Connection;

/**
 * <p>
 * MybatisTransformInterceptor
 * </p>
 *
 * @author lzq
 * @since 2024/12/26 20:02
 */
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class MybatisTransformInterceptor implements Interceptor {

    Log log = LogFactory.getLog(MybatisTransformInterceptor.class);

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        try {
            MyBatisTransformHolder.set(true);
            StatementHandler statementHandler = realTarget(invocation.getTarget());
            MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler);
            MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement");
            String databaseId = mappedStatement.getDatabaseId();
            //当 databaseId 与当前链接数据一致时 ，不执行转换
            String dbType = DatabaseTypeHolder.getDbType();
            if (StrUtil.equalsIgnoreCase(dbType, databaseId)) {
                return invocation.proceed();
            }
            BoundSql boundSql = (BoundSql) metaStatementHandler.getValue("delegate.boundSql");
            String originalSql = boundSql.getSql();
            String result = TransformManager.INSTANCE.parseSQL(originalSql, dbType);
            metaStatementHandler.setValue("delegate.boundSql.sql", result);
            return invocation.proceed();
        } finally {
            MyBatisTransformHolder.remove();
        }
    }

    /**
     * 获取真正的对象
     *
     * @param target 目标对象
     * @param <T>    泛型
     * @return T
     */
    @SuppressWarnings("unchecked")
    public <T> T realTarget(Object target) {
        if (Proxy.isProxyClass(target.getClass())) {
            MetaObject metaObject = SystemMetaObject.forObject(target);
            return realTarget(metaObject.getValue("h.target"));
        }
        return (T) target;
    }

}
